package scalab.utils

object FileUtils{

	import java.io.File
	import scalab.core.dependencies.{Dependency, SoftDependency, HardDependency}
	def copyFile(from: File, to: File): Boolean = {
		import java.io.{FileInputStream, FileOutputStream}
		import java.nio.channels.FileChannel
		val inChannel: FileChannel = new FileInputStream(from).getChannel
    val outChannel: FileChannel = new FileOutputStream(to).getChannel
    try {
    	// magic number for Windows, 64Mb - 32Kb)
      val maxCount: Int = (64 * 1024 * 1024) - (32 * 1024)
      val size: long = inChannel.size
      var position: long = 0
      while (position < size) {
      	position += inChannel.transferTo(position, maxCount, outChannel)
      }
			true
		} 
    catch{
			case _ => false
    }
    finally {
    	if(inChannel != null) inChannel.close
      if(outChannel != null) outChannel.close
    }
  }

	def copyFiles(from: List[File], to: List[File]): Boolean = {
		(from zip to) forall {p => copyFile(p._1, p._2)}
	}

	//canonical paths must be given!
	def copyFile(file: File, fromDir: String, toDir: String) : File = {
		val entryName = /*Path.subPath(*/Path.removePrefix(file.getCanonicalPath, fromDir)//)
		val newFile = new File(toDir + entryName)
		newFile.getParentFile.mkdirs
		copyFile(file, newFile)
		newFile
	}

	


	def copyFiles(files: Iterable[File], fromDir: String, toDir: String): Iterable[File] = 
		files map {f => copyFile(f, fromDir, toDir)}

	def copyDependency(from: Dependency, to: String): Dependency = {
		val newDep = 
			if(from.isSoft)SoftDependency(to) 
			else HardDependency(to)
		newDep.getParentFile.mkdirs
		copyFile(from, newDep)
		newDep
	} 

	def copyDependency(dep: Dependency, fromDir: String, toDir: String): Dependency = {
		//val entryName = /*Path.subPath(*/Path.removePrefix(dep.canonicalPath, fromDir)//)
		copyDependency(dep, toDir + Path.removePrefix(dep.canonicalPath, fromDir))
		/*val newDep = 
			if(dep.isSoft)SoftDependency(toDir + entryName) 
			else HardDependency(toDir + entryName)
		newDep.getParentFile.mkdirs
		copyFile(dep, newDep)
		newDep*/
	}

	def copyDependencies(from: List[Dependency], to: List[String]): List[Dependency] = {
		(from zip to) map {p => copyDependency(p._1, p._2)}
	}

	def copyDependencies(deps: Iterable[Dependency], fromDir: String, toDir: String): Iterable[Dependency] = 
		deps map {d => copyDependency(d, fromDir, toDir)}

	def copyDirectory(fromDir: String, toDir: String): Boolean = 
		copyDirectory(new File(fromDir), new File(toDir))

	def copyDirectory(from: File, to: File): Boolean = {
		if(from.exists && from.isDirectory){
			try{
				((to.exists && to.isDirectory) || to.mkdir) && (
				from.listFiles forall {f => 
					val dest: File = new File(to.getPath + File.separator + f.getName)
					if(f.isDirectory)
						copyDirectory(f, dest)
					else
						copyFile(f, dest)
				})
			}
			catch{
				case _ => false
			}
		}
		else
			false
	}

	def mkDirs(dir: String): Boolean = try{
		val f = new File(dir)
		f.mkdirs
		f.exists
	}
	catch{
		case _ => false
	}

	def sortFiles(files: Iterable[File]) = {
		def file2ordered(f: File): Ordered[File] = new Ordered[File]{
			def compare(that: File): Int = 
				Path.compareDesc(f.getCanonicalPath, that.getCanonicalPath)
		}
		import scala.collection.immutable.TreeSet
		(new TreeSet[File]()(file2ordered _)) ++ files
	}

	def dirSize(dir: File, recursive: Boolean): Long = {
		var size: Long = 0
		dir.listFiles foreach {f =>
			if(f.isDirectory){
				if(recursive)
					size += dirSize(f, recursive)
			}
			else
				size += f.length
		}
		size
	}

	def dirSize(dir: File): Long = dirSize(dir, true)

	def dirSize(dir: String, recursive: Boolean): Long = 
		dirSize(new File(dir), recursive)

	def dirSize(dir: String): Long = dirSize(dir, true)

	def rmDir(dir: File){
		if(dir.exists && dir.isDirectory)dir.listFiles foreach {f =>
			if(f.isDirectory)
				rmDir(f)
			else
				f.delete
		}
		dir.delete
	}

	def emptyDir(dir: File){
		if(dir.exists && dir.isDirectory)dir.listFiles foreach {f =>
			if(f.isDirectory)rmDir(f)
			else f.delete
		}
	}

	def emptyDir(dir: String): Unit = emptyDir(new File(dir))
}
